﻿using BalanceManager.Model;
using BalanceManager.Services;
using BalanceManager.ViewModels;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using System;
using System.Collections.Generic;
using System.Linq;

namespace UnitTests.ViewModelTests
{
    [TestClass]
    public class HistoryProviderTests
    {
        [TestMethod]
        public void CalculatesRightTreeForToday()
        {
            var startDate = new DateTime(2014, 03, 15);
            var endDate = new DateTime(2014, 03, 15, 23, 59, 59, 999);
            var mock = new Mock<IDataService>();
            var todayFundFlows = this.GetFundFlows(startDate);
            var items = this.GetItems();
            mock.Setup(d => d.Items).Returns(items);
            mock.Setup(d => d.LoadFundFlows(startDate, endDate)).Returns(todayFundFlows);
            mock.Setup(d => d.GetItemById(It.IsAny<int>())).Returns((int i) => items.Find(p => p.Id == i));
            var provider = new HistoryProvider(mock.Object);

            var tree = provider.HistoryTree(startDate, Period.Today);
            var food = tree.Children.Single(element => element.Item.ItemName == "Food");
            var clothing = tree.Children.Single(element => element.Item.ItemName == "Clothing");
            var salary = tree.Children.Single(element => element.Item.ItemName == "Salary");
            var transport = tree.Children.Single(element => element.Item.ItemName == "Transport");

            Assert.AreEqual(4, tree.Children.Count);
            Assert.AreEqual(9, food.Item.ExpensesAmount);
            Assert.AreEqual(26, clothing.Item.ExpensesAmount);
            Assert.AreEqual(0, salary.Item.ExpensesAmount);
            Assert.AreEqual(10, salary.Item.ProfitsAmount);
            Assert.AreEqual(0, transport.Item.ExpensesAmount);
        }

        [TestMethod]
        public void CalculatesRightTreeForYesterday()
        {
            var startDate = new DateTime(2014, 03, 14);
            var endDate = new DateTime(2014, 03, 15, 23, 59, 59, 999);
            var mock = new Mock<IDataService>();
            var yesterdayFundFlows = this.GetFundFlows(startDate);
            var items = this.GetItems();
            mock.Setup(d => d.Items).Returns(items);
            mock.Setup(d => d.LoadFundFlows(startDate, endDate)).Returns(yesterdayFundFlows);
            mock.Setup(d => d.GetItemById(It.IsAny<int>())).Returns((int i) => items.Find(p => p.Id == i));
            var provider = new HistoryProvider(mock.Object);

            var tree = provider.HistoryTree(endDate, Period.Yesterday);
            var food = tree.Children.Single(element => element.Item.ItemName == "Food");
            var clothing = tree.Children.Single(element => element.Item.ItemName == "Clothing");
            var salary = tree.Children.Single(element => element.Item.ItemName == "Salary");
            var transport = tree.Children.Single(element => element.Item.ItemName == "Transport");

            Assert.AreEqual(4, tree.Children.Count);
            Assert.AreEqual(9, food.Item.ExpensesAmount);
            Assert.AreEqual(26, clothing.Item.ExpensesAmount);
            Assert.AreEqual(0, salary.Item.ExpensesAmount);
            Assert.AreEqual(10, salary.Item.ProfitsAmount);
            Assert.AreEqual(0, transport.Item.ExpensesAmount);
        }

        [TestMethod]
        public void CalculatesRightTreeForWeek()
        {
            var startDate = new DateTime(2014, 03, 10);
            var endDate = new DateTime(2014, 03, 15, 23, 59, 59, 999);
            var mock = new Mock<IDataService>();
            var fundFlows = this.GetFundFlows(startDate);
            var items = this.GetItems();
            mock.Setup(d => d.Items).Returns(items);
            mock.Setup(d => d.LoadFundFlows(startDate, endDate)).Returns(fundFlows);
            mock.Setup(d => d.GetItemById(It.IsAny<int>())).Returns((int i) => items.Find(p => p.Id == i));
            var provider = new HistoryProvider(mock.Object);

            var tree = provider.HistoryTree(endDate, Period.Week);
            var food = tree.Children.Single(element => element.Item.ItemName == "Food");
            var clothing = tree.Children.Single(element => element.Item.ItemName == "Clothing");
            var salary = tree.Children.Single(element => element.Item.ItemName == "Salary");
            var transport = tree.Children.Single(element => element.Item.ItemName == "Transport");

            Assert.AreEqual(4, tree.Children.Count);
            Assert.AreEqual(9, food.Item.ExpensesAmount);
            Assert.AreEqual(26, clothing.Item.ExpensesAmount);
            Assert.AreEqual(0, salary.Item.ExpensesAmount);
            Assert.AreEqual(10, salary.Item.ProfitsAmount);
            Assert.AreEqual(0, transport.Item.ExpensesAmount);
        }

        [TestMethod]
        public void CalculatesRightTreeForMonth()
        {
            var startDate = new DateTime(2014, 03, 01);
            var endDate = new DateTime(2014, 03, 15, 23, 59, 59, 999);
            var mock = new Mock<IDataService>();
            var fundFlows = this.GetFundFlows(startDate);
            var items = this.GetItems();
            mock.Setup(d => d.Items).Returns(items);
            mock.Setup(d => d.LoadFundFlows(startDate, endDate)).Returns(fundFlows);
            mock.Setup(d => d.GetItemById(It.IsAny<int>())).Returns((int i) => items.Find(p => p.Id == i));
            var provider = new HistoryProvider(mock.Object);

            var tree = provider.HistoryTree(endDate, Period.Month);
            var food = tree.Children.Single(element => element.Item.ItemName == "Food");
            var clothing = tree.Children.Single(element => element.Item.ItemName == "Clothing");
            var salary = tree.Children.Single(element => element.Item.ItemName == "Salary");
            var transport = tree.Children.Single(element => element.Item.ItemName == "Transport");

            Assert.AreEqual(4, tree.Children.Count);
            Assert.AreEqual(9, food.Item.ExpensesAmount);
            Assert.AreEqual(26, clothing.Item.ExpensesAmount);
            Assert.AreEqual(0, salary.Item.ExpensesAmount);
            Assert.AreEqual(10, salary.Item.ProfitsAmount);
            Assert.AreEqual(0, transport.Item.ExpensesAmount);
        }

        [TestMethod]
        public void CalculatesRightTreeForYear()
        {
            var startDate = new DateTime(2014, 01, 01);
            var endDate = new DateTime(2014, 03, 15, 23, 59, 59, 999);
            var mock = new Mock<IDataService>();
            var fundFlows = this.GetFundFlows(startDate);
            var items = this.GetItems();
            mock.Setup(d => d.Items).Returns(items);
            mock.Setup(d => d.LoadFundFlows(startDate, endDate)).Returns(fundFlows);
            mock.Setup(d => d.GetItemById(It.IsAny<int>())).Returns((int i) => items.Find(p => p.Id == i));
            var provider = new HistoryProvider(mock.Object);

            var tree = provider.HistoryTree(endDate, Period.Year);
            var food = tree.Children.Single(element => element.Item.ItemName == "Food");
            var clothing = tree.Children.Single(element => element.Item.ItemName == "Clothing");
            var salary = tree.Children.Single(element => element.Item.ItemName == "Salary");
            var transport = tree.Children.Single(element => element.Item.ItemName == "Transport");

            Assert.AreEqual(4, tree.Children.Count);
            Assert.AreEqual(9, food.Item.ExpensesAmount);
            Assert.AreEqual(26, clothing.Item.ExpensesAmount);
            Assert.AreEqual(0, salary.Item.ExpensesAmount);
            Assert.AreEqual(10, salary.Item.ProfitsAmount);
            Assert.AreEqual(0, transport.Item.ExpensesAmount);
        }

        public List<Item> GetItems()
        {
            var list = new List<Item>
            {
                new Item {Id = 1,  Name = "Food"},
                new Item {Id = 2, Name = "Meat", ParentId = 1},
                new Item {Id = 3, Name = "Bread", ParentId = 1},
                new Item {Id = 4, Name = "Clothing"},
                new Item {Id = 5, Name = "Pants", ParentId = 4},
                new Item {Id = 6, Name = "Jacket", ParentId = 4},
                new Item {Id = 7, Name = "Heat", ParentId = 4},
                new Item {Id = 8, Name = "Salary"},
                new Item {Id = 10, Name = "Transport"},
                new Item {Id = 11, Name = "Taxi", ParentId = 10},
                new Item {Id = 12, Name = "Bus", ParentId = 10}
            };
            return list;
        }

        public List<FundFlow> GetFundFlows(DateTime forDate)
        {
            var list = new List<FundFlow>()
            {
                new FundFlow {Id = 1, ItemId = 1, ItemName = "Food", Amount = 2, Date = forDate, FlowType = FlowType.Expense},
                new FundFlow {Id = 2, ItemId = 2, ItemName = "Meat", Amount = 3, Date = forDate, FlowType = FlowType.Expense},
                new FundFlow {Id = 3, ItemId = 3, ItemName = "Bread", Amount = 4, Date = forDate, FlowType = FlowType.Expense},
                new FundFlow {Id = 4, ItemId = 4, ItemName = "Clothing", Amount = 5, Date = forDate, FlowType = FlowType.Expense},
                new FundFlow {Id = 5, ItemId = 5, ItemName = "Pants", Amount = 6, Date = forDate, FlowType = FlowType.Expense},
                new FundFlow {Id = 6, ItemId = 6, ItemName = "Jacket", Amount = 7, Date = forDate, FlowType = FlowType.Expense},
                new FundFlow {Id = 7, ItemId = 7, ItemName = "Heat", Amount = 8, Date = forDate, FlowType = FlowType.Expense},
                new FundFlow {Id = 7, ItemId = 8, ItemName = "Salary", Amount = 10, Date = forDate, FlowType = FlowType.Profit}
            };
            return list;
       }
    }
}
